package com.example.rwq_test.agent;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.TimeUnit;

/**
 * @Description
 *  1. 主要是在通过反射来实现方法: java.util.concurrent.CopyOnWriteArrayList#removeRange(int, int)
 *  2. java.util.concurrent.CopyOnWriteArrayList#removeRange(int, int)是一个default方法不能通过继承调用；
 *  3. 模拟多个线程向list中添加元素， 一个线程批量取出元素处理
 *
 * @Author renweiqiang
 * @Date 2024/4/19 下午5:02
 */
public class DefaultMethodInvoke {
    private static final CopyOnWriteArrayList<Integer> list = new CopyOnWriteArrayList<>();
    public static void main(String[] args) throws InterruptedException {
        // 添加数据
        addData();

        TimeUnit.MILLISECONDS.sleep(500);

        //处理数据
        handleData();
    }

    /**
     * 处理数据
     */
    private static void handleData() {
        new Thread(() -> {
            // 获取数据
            List<Integer> list1 = new ArrayList<>(list);
            try {
                //模拟处理业务
                TimeUnit.MILLISECONDS.sleep(50);

                // 移除数据
                Method removeRange = getInvokeMethod(CopyOnWriteArrayList.class, "removeRange", int.class, int.class);
                invoke(removeRange, list, 0, list1.size());
            } catch (Exception e) {
                e.printStackTrace();
            }
        }).run();
    }

    /**
     * 添加数据
     */
    private static void addData() {
        for (int i = 0; i < 2; i++) {
            new Thread(() -> {
                for (int i1 = 0; i1 < 500000; i1++) {
                    list.add(i1);
                    try {
                        TimeUnit.MILLISECONDS.sleep(10);
                    } catch (InterruptedException e) {

                    }
                }
            }).run();
        }
    }

    private static void invoke(Method removeRange, CopyOnWriteArrayList<Integer> list, Object... args) {
        try {
            removeRange.invoke(list, args);
            removeRange.setAccessible(false);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        }
    }

    public static <T> Method getInvokeMethod(Class<T> tClass, String methodName, Class<?>... parameterTypes) {
        try {
            Method method = tClass.getDeclaredMethod(methodName, parameterTypes);
            method.setAccessible(true);
            return method;
        } catch (Exception e) {
            return null;
        }
    }
}